#pragma once

#include "stdafx.h"

template<class T>
class CAsyncCallback : public IMFAsyncCallback
{
public:
	typedef HRESULT (T::*AsyncInvoke)(IMFAsyncResult* pAsyncResult);
	typedef HRESULT (T::*AsyncInvoke2)();
	typedef HRESULT (T::*AsyncInvokeWithParameters)(PVOID p);
private:
	T* Parent;
	AsyncInvoke pfn = NULL;
	AsyncInvoke2 pfn2 = NULL;
	AsyncInvokeWithParameters pfn3 = NULL;
	PVOID pParameters = NULL;
public:
	CAsyncCallback(T* P,AsyncInvoke fn)
	{
		Parent = P;
		pfn = fn;
	}
	CAsyncCallback(T* P,AsyncInvoke2 fn)
	{
		Parent = P;
		pfn2 = fn;
	}
	CAsyncCallback(T* P,AsyncInvokeWithParameters fn,PVOID pv)
	{
		Parent = P;
		pfn3 = fn;
		pParameters = pv;
	}
public:
	IFACEMETHODIMP QueryInterface(REFIID iid,void** ppv)
	{
		if (ppv == NULL)
			return E_POINTER;
		if (iid == IID_IUnknown || iid == IID_IMFAsyncCallback)
		{
			*ppv = static_cast<IUnknown*>(this);
			AddRef();
			return S_OK;
		}
		*ppv = NULL;
		return E_NOINTERFACE;
	}
	IFACEMETHODIMP_(ULONG) AddRef()
	{
		return Parent->AddRef();
	}
	IFACEMETHODIMP_(ULONG) Release()
	{
		return Parent->Release();
	}
public:
	STDMETHODIMP GetParameters(PDWORD,PDWORD)
	{
		return E_NOTIMPL;
	}
	STDMETHODIMP Invoke(IMFAsyncResult* pAsyncResult)
	{
		if (pfn) //AsyncInvoke
			return (Parent->*pfn)(pAsyncResult);
		else if (pfn2) //AsyncInvoke2
		{
			HRESULT hr = (Parent->*pfn2)();
			if (pAsyncResult)
				pAsyncResult->SetStatus(hr);
			return S_OK;
		}else if (pfn3) //AsyncInvokeWithParameters
		{
			HRESULT hr = (Parent->*pfn3)(pParameters);
			if (pAsyncResult)
				pAsyncResult->SetStatus(hr);
			return S_OK;
		}else
			return MF_E_INVALIDTYPE;
	}
};